// 这个属性用于隐藏未使用代码的警告。
#![allow(dead_code)]

#[derive(Debug)]
struct Study {
    name: String,
    target: String,
    spend: i32,
}

impl Study {
    fn new(name: String, target: String, spend: i32) -> Study {
        Study {
            name,
            target,
            spend,
        }
    }

    fn get_spend(&self) -> i32 {
        self.spend
    }

    fn show(&self) {
        println!(
            "name is :{} target is :{} spend is :{}",
            self.name, self.target, self.spend
        )
    }
}

// 结构体作为参数
fn show(s: &Study) {
    println!(
        "name is :{} target is :{} spend is :{}",
        s.name, s.target, s.spend
    )
}

// 结构体作为返回值
fn get_instance(name: String, target: String, spend: i32) -> Study {
    Study {
        name,
        target,
        spend,
    }
}

#[derive(Debug)]
struct Person {
    name: String,
    age: u8,
}

// 单元结构体
struct Unit;

// 元祖结构体
struct Pair(i32, f32);

// 带有两个字段的结构体
#[derive(Debug)]
struct Point {
    x: f32,
    y: f32,
}

// 结构体可以作为另一个结构体的字段
#[derive(Debug)]
struct Rectangle {
    // 可以通过指定左上角和右下角的位置来定义一个矩形
    top_left: Point,
    bottom_right: Point,
}

// 添加一个 rect_area 函数来计算 Rectangle 的面积（尝试使用嵌套解构）。
fn rect_area(rectangle: Rectangle) -> f32 {
    let Rectangle {
        top_left: Point { x: tl_x, y: tl_y },
        bottom_right: Point { x: br_x, y: br_y },
    } = rectangle;
    let length = tl_x - br_x;
    let high = tl_y - br_y;
    length.abs() * high.abs()
}

impl Rectangle {
    fn get_area(&self) -> f32 {
        let length = self.top_left.x - self.bottom_right.x;
        let high = self.top_left.y - self.bottom_right.y;
        length.abs() * high.abs()
    }
}
// 添加一个 square 函数，它接受一个 Point 和一个 f32 作为参数，返回一个 Rectangle，
// 其左上角在该点上，宽度和高度都等于 f32 参数。
fn square(p: Point, num: f32) -> Rectangle {
    let p02 = Point {
        x: p.x + num,
        y: p.y - num,
    };
    Rectangle {
        top_left: p,
        bottom_right: p02,
    }
}

fn main() {
    // 使用字段初始化简写语法创建结构体
    let name = String::from("Peter");
    let age = 27;
    let peter = Person { name, age };
    // 打印结构体的调试信息
    println!("{:?}", peter);
    // 实例化一个 Point
    let point: Point = Point { x: 5.2, y: 0.4 };
    let another_point: Point = Point { x: 10.3, y: 0.2 };
    println!("点的坐标: ({} {})", point.x, point.y);
    // 使用结构体更新语法创建新的点
    let bottom_right = Point {
        x: 10.3,
        ..another_point
    };
    // `bottom_right.y` 与 `another_point.y` 相同,
    // 因为我们使用了 `another_point` 的该字段
    println!("第二个点: ({} {})", bottom_right.x, bottom_right.y);
    // 使用 let 绑定结构点
    let Point {
        x: left_edge,
        y: top_edge,
    } = point;
    let _rectangle = Rectangle {
        // 结构体实例化也是一个表达式
        top_left: Point {
            x: left_edge,
            y: top_edge,
        },
        bottom_right: bottom_right,
    };
    println!("rectangle: {:?}", _rectangle);
    println!("rectangle->get_area(): {:?}", _rectangle.get_area());
    println!("rectangle->rect_area(): {:?}", rect_area(_rectangle));

    let new_rect = square(Point { x: 2.8, y: 6.3 }, 5.5);
    println!("new_rect: {:?}", new_rect);
    println!("new_rect->get_area(): {:?}", new_rect.get_area());
    println!("new_rect->rect_area(): {:?}", rect_area(new_rect));

    // 实例化一个单元结构体
    let _unit = Unit;

    // 实例化一个元组结构体
    let pair = Pair(1, 0.1);
    // 访问元组结构体的字段
    println!("pair 包含 {:?} 和 {:?}", pair.0, pair.1);
    // 解构一个元组结构体
    let Pair(int_value, float_value) = pair;
    println!("pair 包含 {:?} 和 {:?}", int_value, float_value);

    let study = Study {
        name: String::from("Rust入门指南"),
        target: String::from("掌握Rust基本语法"),
        spend: 3,
    };
    println!("{:?}", study);
    println!("{:?}", study.name);
    println!("{}", study.target);
    println!("{}", study.spend);
    show(&study);

    let s3 = get_instance(
        String::from("Rust入门指南"),
        String::from("掌握Rust基本语法"),
        3,
    );
    println!("{:?}", s3);
    println!("s3占用了 {} 字节的内存大小", std::mem::size_of_val(&s3));

    println!("s3.spend {}", s3.get_spend());

    let s4 = Study::new(
        String::from("Rust权威指南"),
        String::from("深入了解Rust细节内容"),
        10,
    );
    show(&s4);
    s4.show();
}